package com.zero.insp.controller;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.zero.insp.common.PJson;
import com.zero.insp.common.PPageInfo;
import com.zero.insp.common.PResult;
import com.zero.insp.domain.TUserInfo;
import com.zero.insp.domain.TUserInfoExample;
import com.zero.insp.services.UserService;
import com.zero.insp.shiro.ShiroPasswordHelper;
import com.zero.insp.utils.ReadExcelUtils;
import com.zero.insp.utils.RunnerUtil;
import com.zero.insp.views.User;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @author : pengjie
 * @PackageName : com.zero.insp.controller
 * @Description : 用户管理
 * @email : 627799251@qq.com
 * @Date : 2019/3/26 13:37
 */
@Api(value="管理员后台页面请求接口")
@RestController
public class WebUserInfoController {

    private static final Logger logger = LoggerFactory.getLogger(WebUserInfoController.class);

    private static LoadingCache<String, Long> cache = null;

    static {
        cache = CacheBuilder.newBuilder().expireAfterWrite(5, TimeUnit.MINUTES)
                .build(new CacheLoader<String, Long>() {

                    @Override
                    public Long load(String key) throws Exception {
                        return 0L;
                    }
                });
    }

    @Autowired
    private UserService userService;

    @ApiOperation("用户列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name="user_type",value="用户类型",dataType="string", paramType = "query",example="高级用户"),
            @ApiImplicitParam(name="user_account",value="用户账号",dataType="string", paramType = "query")
    })
    @RequiresUser
    @GetMapping("/web/v1/user/list")
    public PResult<PPageInfo<TUserInfo>> list(String user_type, String user_account,
                                              @RequestParam(name= "page",defaultValue = "1")int page,
                                              @RequestParam(name= "size",defaultValue = "10")int size) {

        TUserInfoExample example = new TUserInfoExample();
        TUserInfoExample.Criteria criteria =  example.createCriteria();
        if (user_type != null){
            criteria.andTypeEqualTo(user_type);
        }

        if (user_account != null){
            criteria.andAccountEqualTo(user_account);
        }

        PPageInfo<TUserInfo> users = userService.query(example, page, size);

        return new PResult<>(users);
    }

    @ApiOperation("用户新增")
    @ApiImplicitParams({
            @ApiImplicitParam(name="user_type",value="用户类型",dataType="string", required = true, paramType = "query",example="高级用户"),
            @ApiImplicitParam(name="user_name",value="用户姓名",dataType="string", required = true, paramType = "query"),
            @ApiImplicitParam(name="user_account",value="用户账号",dataType="string", required = true, paramType = "query"),
            @ApiImplicitParam(name="pwd",value="用户密码",dataType="string", required = true, paramType = "query"),
            @ApiImplicitParam(name="describ",value="用户描述",dataType="string", paramType = "query")

    })
    @RequiresUser
    @PostMapping("/web/v1/user/add")
    public PJson add(String user_type, String user_name, String user_account, String pwd, String describ) {

        //1.用户账号是否存在
        if (userService.exist(user_account)){
            return PJson.fail("user add", "用户账户已存在，请重新输入");
        }
        if (userService.existName(user_name)){
            return PJson.fail("user add", "用户账户真实姓名已存在，请重新输入");
        }
        String salt = ShiroPasswordHelper.genPasswdSalt();
        //2.salt
        String password = ShiroPasswordHelper.encodePassword(pwd, salt);

        TUserInfo userInfo = new TUserInfo();
        userInfo.setName(user_name);
        userInfo.setType(user_type);
        userInfo.setAccount(user_account);
        userInfo.setPwd(password);
        userInfo.setSalt(salt);
        userInfo.setStatus(0);
        userInfo.setCreateTime(new Date());
        userInfo.setDescrib(describ);

        userService.add(userInfo);

        return PJson.succ();
    }
    @ApiOperation("用户编辑")
    @ApiImplicitParams({
            @ApiImplicitParam(name="user_id",value="用户ID",dataType="long", required = true, paramType = "query"),
            @ApiImplicitParam(name="user_type",value="用户类型",dataType="string", required = true, paramType = "query",example="高级用户"),
            @ApiImplicitParam(name="user_name",value="用户姓名",dataType="string", required = true, paramType = "query"),
            @ApiImplicitParam(name="pwd",value="用户密码",dataType="string", paramType = "query"),
            @ApiImplicitParam(name="describ",value="用户描述",dataType="string", paramType = "query")

    })
    @RequiresUser
    @PostMapping("/web/v1/user/edit")
    public PJson edit(@RequestParam(name= "user_id",required = true)long user_id,
                      String user_type, String user_name, String pwd, String describ) {
        //1.用户账号是否存在
        if (userService.findUserById(user_id) == null){
            return PJson.fail("user edit", "当前用户id不存在账号信息，请重新输入");
        }


        TUserInfo userInfo = new TUserInfo();
        userInfo.setName(user_name);
        userInfo.setType(user_type);
        if (pwd != null){
            String salt = ShiroPasswordHelper.genPasswdSalt();
            String password = ShiroPasswordHelper.encodePassword(pwd, salt);
            userInfo.setPwd(password);
            userInfo.setSalt(salt);
        }
        userInfo.setDescrib(describ);

        userService.edit(userInfo, user_id);

        return PJson.succ();
    }
    @ApiOperation("用户删除")
    @ApiImplicitParam(name="user_id",value="用户ID",dataType="long", paramType = "query")
    @RequiresUser
    @DeleteMapping("/web/v1/user/del")
    public PJson del(@RequestParam(name= "user_id",required = true)long user_id) {
        userService.delete(user_id);

        return PJson.succ();
    }
    @ApiOperation("用户禁用")
    @ApiImplicitParam(name="user_id",value="用户ID",dataType="long", paramType = "query")
    @RequiresUser
    @PutMapping("/web/v1/user/dis")
    public PJson dis(@RequestParam(name= "user_id",required = true)long user_id) {

        TUserInfo userInfo = new TUserInfo();
        userInfo.setStatus(1);

        userService.edit(userInfo, user_id);

        return PJson.succ();
    }
    @ApiOperation("用户启用")
    @ApiImplicitParam(name="user_id",value="用户ID",dataType="long", paramType = "query")
    @RequiresUser
    @PutMapping("/web/v1/user/enable")
    public PJson enable(@RequestParam(name= "user_id",required = true)long user_id) {

        TUserInfo userInfo = new TUserInfo();
        userInfo.setStatus(0);

        userService.edit(userInfo, user_id);

        return PJson.succ();
    }
    @ApiOperation("用户批量删除")
    @ApiImplicitParam(name="user_ids",value="用户IDS,格式以逗号隔开",dataType="long", paramType = "query",example = "13,15,17")
    @RequiresUser
    @DeleteMapping("/web/v1/user/bdel")
    public PJson bdel(@RequestParam(name= "user_ids",required = true)String user_ids) {

        String[] ids = user_ids.split(",");
        for(int i=0; i<ids.length; i++){
            userService.delete(Long.valueOf(ids[i]));
        }

        return PJson.succ();
    }
    @ApiOperation("用户批量导入")
    @RequiresUser
    @PostMapping("/web/v1/user/batch")
    public PJson batch(MultipartFile batch_file) throws Exception {

        User user = (User) SecurityUtils.getSubject().getPrincipal();
        String cacheKey = user.getUid()+batch_file.getOriginalFilename();

        if (cache.get(cacheKey) == 1){
            return PJson.fail().msg("请勿频繁上传相同文件，请5分钟后再试。");
        }

        cache.put(cacheKey, 1L);

        RunnerUtil.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    batchWork(batch_file);
                } catch (IOException e) {
                    logger.info("导入用户账号数据文件出现问题", e);
                }
            }
        });


        return PJson.succ();
    }

    private void batchWork(MultipartFile batch_file) throws IOException {

        Workbook workbook = ReadExcelUtils.getWorkbok(batch_file.getInputStream(),batch_file.getOriginalFilename());
        //Workbook workbook = WorkbookFactory.create(is); // 这种方式 Excel2003/2007/2010都是可以处理的

        int sheetCount = workbook.getNumberOfSheets(); // Sheet的数量
        /**
         * 设置当前excel中sheet的下标：0开始
         */
        Sheet sheet = workbook.getSheetAt(0);   // 遍历第三个Sheet
        // 为跳过第一行目录设置count
        int count = 0;
        for (Row row : sheet) {
            logger.info("正在导入用户账号数据，当前用户:" + row.getCell(0).getStringCellValue());

            try {
                // 跳过第1行的目录
                if (count < 1) {
                    count++;
                    continue;
                }
                //如果当前行没有数据，跳出循环
                if (row.getCell(0).toString().equals("")) {
                    continue;
                }
                String user_name = row.getCell(0).getStringCellValue();
                String user_type = row.getCell(1).getStringCellValue();
                String user_account = row.getCell(2).getStringCellValue();
                String user_pwd = row.getCell(3).getStringCellValue();
                String user_desc = row.getCell(4).getStringCellValue();

                //1.用户账号是否存在
                if (userService.exist(user_account)){
                    continue;
                }
                if (userService.existName(user_name)){
                    continue;
                }
                String salt = ShiroPasswordHelper.genPasswdSalt();
                //2.salt
                String password = ShiroPasswordHelper.encodePassword(user_pwd, salt);

                TUserInfo userInfo = new TUserInfo();
                userInfo.setName(user_name);
                userInfo.setType(user_type);
                userInfo.setAccount(user_account);
                userInfo.setPwd(password);
                userInfo.setSalt(salt);
                userInfo.setStatus(0);
                userInfo.setDescrib(user_desc);

                userInfo.setCreateTime(new Date());

                userService.add(userInfo);

            }catch (Exception e){
                logger.info("当前用户账号数据异常，用户姓名:" + row.getCell(0).getStringCellValue(), e);
            }
        }
        logger.info("导入用户账号数据完成...");
    }

    @ApiOperation("用户修改密码")
    @ApiImplicitParams({
            @ApiImplicitParam(name="user_id",value="用户ID",dataType="long", paramType = "query"),
            @ApiImplicitParam(name="old_pwd",value="旧密码",dataType="string", paramType = "query"),
            @ApiImplicitParam(name="new_pwd",value="新密码",dataType="string", paramType = "query")
    })
    @RequiresUser
    @PutMapping("/web/v1/user/reset")
    public PJson reset(@RequestParam(name= "user_id",required = true)long user_id,
                       @RequestParam(name= "old_pwd",required = true)String old_pwd,
                       @RequestParam(name= "new_pwd",required = true)String new_pwd) {

        TUserInfo userInfo = userService.findUserById(user_id);

        if (!checkPwd(old_pwd, userInfo.getSalt(), userInfo.getPwd())){
            return PJson.fail().msg("用户旧密码错误，请重新输入");
        }

        String nsalt = ShiroPasswordHelper.genPasswdSalt();
        String npwd = ShiroPasswordHelper.encodePassword(new_pwd, nsalt);

        userInfo.setPwd(npwd);
        userInfo.setSalt(nsalt);

        userService.edit(userInfo, user_id);

        return PJson.succ();
    }

    private boolean checkPwd(String old_pwd, String salt, String origin){

        if (origin.equals(ShiroPasswordHelper.encodePassword(old_pwd, salt))){
            return true;
        }

        return false;
    }
}
